﻿/*********************************************
Copyright (c) 2013 All Right Reserved, bixaps

This source is subject to the Microsoft Permissive License.
All other rights reserved.      

THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Author: Raj Bandi
Email: raj.bandi@hotmail.com

Expander control
*********************************************/

(function () {
    "use strict";

    WinJS.Namespace.define("Bixaps.UI",
        {
            Expander: WinJS.Class.define(function (element, options) {
                this.element = element || document.createElement("div");

                if (!this.element.parentNode) {
                    document.body.appendChild(this.element);
                }

                this._options = options || {};
                this.element.winControl = this;
                this._headerDataSource = {};
                this._contentDataSource = {};

                this._dataSource = {};


                this._parentListItem = null;
                this._parentListView = null;

                this._collapseImage = '';
                this._expandImage = '';

                this._create();

                WinJS.UI.setOptions(this, this._options);

                this._initLayout();

            },
                {
                    _icons: null,
                    _expanded: false,
                    _showPointer: true,
                    _disabled: false,
                    _freezeHeader: false,
                    _expandDirection: null,
                    _pointerPosition: null,
                    _create: function () {
                        this._contentTemplate = document.createElement("div");
                        this._headerPointer = document.createElement("div");
                        this._headerTemplateContainer = document.createElement("div");
                        this._headerTemplate = document.createElement("div");

                        this._headerContainer = document.createElement("div");
                        this._contentContainer = document.createElement("div");
                        this._controlContainer = document.createElement("div");
                        this._controlWrapper = document.createElement("div");
                    },
                    _initLayout: function () {

                        var element = this.element;
                        element.innerHTML = '';

                        this._headerContainer.className = '';
                        this._contentContainer.className = '';
                        this._headerPointer.className = '';
                        this._headerTemplateContainer.className = '';

                        WinJS.Utilities.addClass(element, "win-expander");
                        WinJS.Utilities.addClass(this._headerContainer, "win-expander-header");
                        WinJS.Utilities.addClass(this._contentContainer, "win-expander-content");
                        WinJS.Utilities.addClass(this._headerPointer, "win-expander-arrow");
                        WinJS.Utilities.addClass(this._headerTemplateContainer, "win-expander-headertext");


                        if (!this._expandDirection || this._expandDirection == '')
                            this._expandDirection = 'down';

                        if (!this._pointerPosition || this._pointerPosition == '')
                            this._pointerPosition = 'right';

                        if (this._expandDirection == "down" || this._expandDirection == "up") {
                            if (this._pointerPosition == "left") {
                                this._headerContainer.appendChild(this._headerPointer);
                                this._headerContainer.appendChild(this._headerTemplateContainer);
                            } else {
                                this._headerContainer.appendChild(this._headerTemplateContainer);
                                this._headerContainer.appendChild(this._headerPointer);
                            }

                            if (this._expandDirection == "up") {

                                element.appendChild(this._contentContainer);
                                element.appendChild(this._headerContainer);
                            } else {
                                element.appendChild(this._headerContainer);
                                element.appendChild(this._contentContainer);

                            }
                        } else if (this._expandDirection == 'right' || this._expandDirection == 'left') {

                            if (this._pointerPosition == "bottom") {

                                this._headerContainer.appendChild(this._headerTemplateContainer);
                                this._headerContainer.appendChild(this._headerPointer);
                            } else {
                                this._headerContainer.appendChild(this._headerPointer);
                                this._headerContainer.appendChild(this._headerTemplateContainer);
                            }

                            if (this._expandDirection == 'left') {

                                element.appendChild(this._contentContainer);
                                element.appendChild(this._headerContainer);

                            } else {
                                element.appendChild(this._headerContainer);
                                element.appendChild(this._contentContainer);
                            }

                        }


                        WinJS.Utilities.addClass(this._headerPointer, 'win-expander-arrow-' + this._pointerPosition);
                        WinJS.Utilities.addClass(element, "win-expander-" + this._expandDirection);
                        WinJS.Utilities.addClass(element, "collapsed");

                        this._updateArrows();
                        this._updateHeader();
                        this._updateContent();

                        this._hideContent();
                        element.setAttribute("aria-expanded", this._expanded);
                        element.setAttribute("aria-disabled", this._disabled);

                        var that = this;
                        this._headerContainer.onclick = function () {
                            if (!that._freezeHeader) {
                                that._expanded = !that._expanded;
                                that._refresh();
                            }
                        };

                        setTimeout(function() {
                            that._adjustDimensions();
                        }, 10);
                       
                    },

                    _updateHeader: function () {
                        if (this._headerTemplate.winControl) {
                            this._headerTemplateContainer.innerHTML = '';
                            this._headerTemplate.winControl.render(this._headerDataSource, this._headerTemplateContainer);
                        }
                    },
                    _updateContent: function () {

                        if (this._contentTemplate.winControl) {
                            this._contentContainer.innerHTML = '';


                            if (this._contentDataSource instanceof Array) {
                                for (var index in this._contentDataSource) {
                                    this._contentTemplate.winControl.render(this._contentDataSource[index], this._contentContainer);
                                }

                            } else if (this._contentDataSource instanceof Function) {


                            } else {

                                this._contentTemplate.winControl.render(this._contentDataSource, this._contentContainer);
                            }
                        }

                    },
                    _updateArrows: function () {

                        switch (this._expandDirection) {
                            case 'up':

                                if (!this._icons) {
                                    this._icons = {
                                        expand: Bixaps.Util.Icons.ARROW_HEAD_UP, //up
                                        collapse: Bixaps.Util.Icons.ARROW_HEAD_LEFT //left
                                    };
                                }

                                break;
                            case 'left':
                                if (!this._icons) {
                                    this._icons = {
                                        expand: Bixaps.Util.Icons.ARROW_HEAD_LEFT, //left
                                        collapse: Bixaps.Util.Icons.ARROW_HEAD_DOWN //down
                                    };
                                }

                                break;
                            case 'right':
                                if (!this._icons) {
                                    this._icons = {
                                        expand: Bixaps.Util.Icons.ARROW_HEAD_RIGHT, //right
                                        collapse: Bixaps.Util.Icons.ARROW_HEAD_DOWN //down
                                    };
                                }
                                break;
                            default:
                                if (!this._icons) {
                                    this._icons = {
                                        expand: Bixaps.Util.Icons.ARROW_HEAD_DOWN, //down
                                        collapse: Bixaps.Util.Icons.ARROW_HEAD_RIGHT //right
                                    };
                                }
                                break;

                        }
                        try {


                            var expandImage = this._icons.expand || '';
                            var collapseImage = this._icons.collapse || '';

                            if (expandImage.indexOf("data:image") >= 0 || expandImage.indexOf(".png") >= 0
                                || expandImage.indexOf(".jpg") >= 0) {
                                var img = document.createElement('img');
                                img.src = expandImage;

                                expandImage = img;
                            }
                            if (collapseImage.indexOf("data:image") >= 0 || collapseImage.indexOf(".png") >= 0
                                || collapseImage.indexOf(".jpg") >= 0) {
                                var img = document.createElement('img');
                                img.src = collapseImage;
                                collapseImage = img;

                            }
                        } catch (e) {


                        }
                        this._expandImage = expandImage;
                        this._collapseImage = collapseImage;
                    },
                    //adjust dimensions 
                    _adjustDimensions: function () {
                        
                        //bug fix for hidden parent container
                        this._contentContainer.style.display = '';
                        var parentNode, parentClass;
                        var node = this.element.parentNode;
                        if (node != document.body) {
                            while (node != null && node != 'undefined') {
                                var nstyle = document.defaultView.getComputedStyle(node, null);
                                if (nstyle) {
                                    var display = nstyle.getPropertyValue('display');
                                    if (display == 'none') {
                                        parentClass = node.className;
                                        node.style.display = '';
                                        node.className = '';
                                        parentNode = node;
                                        break;
                                    }
                                }
                                if (node == document.body)
                                    break;
                                node = node.parentNode;

                            }
                        }

                        //recalculate header and content dimensions
                        var cw = this._contentContainer.offsetWidth;
                        var ch = this._contentContainer.offsetHeight;
                        
                        if (this._isUp || this._isDown) {
                            this._headerContainer.style.minWidth = cw + "px";
                            this._headerTemplateContainer.style.maxWidth = (cw - this._headerPointer.offsetWidth - 15) + "px";
                        } else {

                            var headerStyle = document.defaultView.getComputedStyle(this._headerContainer, null);
                            var maxWidth = "250px";
                            if (headerStyle) {
                                var mw = headerStyle.getPropertyValue('max-width');
                                if (mw)
                                    maxWidth = mw;
                            }
                            this._headerContainer.style.maxWidth = maxWidth;

                            cw = (this.element.offsetWidth - this._headerContainer.offsetWidth) - 15;
                            this._contentContainer.style.maxWidth = cw + "px";

                            var oh = this._contentContainer.offsetHeight;
                            
                            this._headerContainer.style.minHeight = (ch>oh)?ch:oh + "px";
                            
                        }

                        this._contentContainer.style.display = 'none';

                        //refresh 
                        var oldExpand = this._expanded;
                        var that = this;
                        if (oldExpand) {
                            that._refresh(10);
                        }

                        //bugfix for hidden parent containers
                        if (parentNode) {
                            if (parentClass != '')
                                parentNode.className = parentClass;
                            else
                                parentNode.style.display = 'none';
                        }
                    }

                    //Refresh expander
                    , _refresh: function (duration) {

                        var content = this._contentContainer;
                        if (this._expanded) {
                            this._showContent();

                            if (this._isLeft || this._isRight) {

                                Bixaps.UI.Animation.slide(content, { direction: 'right',duration:duration, wrapperStyle: 'float:left;' });
                            } else {
                                Bixaps.UI.Animation.slide(content, { direction: 'down', duration: duration });
                            }

                        } else {
                            this._hideContent();
                           
                            if (this._expandDirection == "left" || this._expandDirection == "right") {

                                Bixaps.UI.Animation.slide(content, { direction: 'left', mode: 'hide', wrapperStyle: 'float:left;' });
                               
                            } else {
                                Bixaps.UI.Animation.slide(content, { direction: 'up', mode: 'hide' });

                            }
                        }

                        this.element.setAttribute("aria-expanded", this._expanded);

                        if (this._freezeHeader) {
                            if (!WinJS.Utilities.hasClass(this._headerContainer, 'freezeHeader')) {
                                WinJS.Utilities.addClass(this._headerContainer, 'freezeHeader');
                            }
                        } else {
                            if (WinJS.Utilities.hasClass(this._headerContainer, 'freezeHeader')) {
                                WinJS.Utilities.removeClass(this._headerContainer, 'freezeHeader');
                            }
                        }

                        this._headerPointer.style.display = this._showPointer ? '' : 'none';

                    },
                    _showContent: function () {

                        WinJS.Utilities.removeClass(this.element, "collapsed");
                        WinJS.Utilities.addClass(this.element, "expanded");
                        this._updateArrowImage(this._expandImage);

                        this.dispatchEvent("expand");


                    },
                    _hideContent: function () {
                        WinJS.Utilities.removeClass(this.element, "expanded");
                        WinJS.Utilities.addClass(this.element, "collapsed");

                        this._updateArrowImage(this._collapseImage);
                        this.dispatchEvent("collapse");
                    },
                    _updateArrowImage: function (img) {
                        if (img instanceof HTMLImageElement) {
                            this._headerPointer.innerHTML = '';
                            this._headerPointer.appendChild(img);
                        } else {
                            this._headerPointer.innerHTML = window.toStaticHTML(img);
                        }
                    },
                    _adjustListView: function () {

                        var parent = this._parentListItem;

                        if (!Bixaps.Util.IsNull(parent)) {

                            var top = Bixaps.Util.getTop(parent);

                            try {
                                var h = WinJS.Utilities.getContentHeight(parent);

                                if (h > 0) {

                                    parent.style.height = h + "px";
                                    var nextTop = top + h + 5;
                                    var next = parent.nextSibling;
                                    while (!Bixaps.Util.IsNull(next)) {

                                        if (next.nodeType == 1) {
                                            next.style.top = nextTop + "px";
                                            top = Bixaps.Util.getTop(next);
                                            h = WinJS.Utilities.getContentHeight(next);
                                            nextTop = top + h + 5;
                                        }
                                        next = next.nextSibling;
                                    }


                                }
                            } catch (e) {
                            }


                        }
                    },
                    _isLeft: {
                        get: function () {
                            return (this._expandDirection == 'left');
                        }
                    },
                    _isRight: {
                        get: function () {
                            return (this._expandDirection == 'right');
                        }
                    },
                    _isDown: {
                        get: function () {
                            return (this._expandDirection == 'down');
                        }
                    },
                    _isUp: {
                        get: function () {
                            return (this._expandDirection == 'up');
                        }
                    },
                    //public methods
                    expanded: {
                        get: function () {
                            return this._expanded;
                        },
                        set: function (value) {
                            this._expanded = value;
                        }
                    },
                    expand: function () {
                        this._expanded = true;
                        this._refresh();
                    },
                    collapse: function () {
                        this._expanded = false;
                        this._refresh();
                    },
                    headerTemplate: {
                        set: function (value) {
                            if (value) {

                                this._headerTemplate = value;
                            }
                        }
                    }
                    ,
                    contentTemplate: {
                        set: function (value) {
                            if (value) {
                                this._contentTemplate = value;
                            }
                        }
                    },
                    dataSource:
                        {
                            set: function (data) {
                                if (data instanceof Array) {
                                    if (data[0]) {
                                        this._headerDataSource = data[0];
                                    }
                                    if (data[1]) {
                                        this._contentDataSource = data[1];
                                    }
                                }
                                else
                                    if (data instanceof Object) {

                                        if (data.header) {
                                            this._headerDataSource = data.header;
                                        }
                                        if (data.content) {
                                            this._headerDataSource = data.content;
                                        }
                                    }
                            }
                        },
                    headerDataSource: {
                        set: function (data) {
                            this._headerDataSource = data;
                        }
                    },
                    contentDataSource: {
                        set: function (data) {
                            this._contentDataSource = data;
                        }
                    },
                    expandDirection: {
                        get: function () {
                            return this._expandDirection;
                        },
                        set: function (dir) {

                            this._expandDirection = dir;
                        }
                    },
                    pointerPosition: {
                        get: function () {
                            return this._pointerPosition;
                        },
                        set: function (val) {

                            this._pointerPosition = val;
                        }
                    },
                    freezeHeader: {
                        get: function () {
                            return this._freezeHeader;
                        },
                        set: function (val) {

                            this._freezeHeader = val;
                        }
                    },
                    showArrow: {
                        get: function () {
                            return this._showPointer;
                        },
                        set: function (val) {

                            this._showPointer = val;
                        }
                    },
                    icons: {
                        set: function (val) {
                            this._icons = val;
                            this._updateArrows();
                        }
                    },
                    disabled: {
                        get: function () {
                            return this._disabled;
                        },
                        set: function (val) {

                            this._disabled = val;
                        }
                    },
                    forceLayout: function () {
                        this._expandImage = '';
                        this._collapseImage = '';
                        this._initLayout();
                    },
                    parentListItem: {
                        set: function (item) {
                            this._parentListItem = item;
                        }
                    },
                    parentListView: {
                        set: function (view) {
                            this._parentListView = view;
                        }
                    }

                }
            )
        });

    WinJS.Class.mix(Bixaps.UI.Expander, WinJS.Utilities.createEventProperties(
           "expand"
          , "collapse"
      ), WinJS.UI.DOMEventMixin);
})();

